﻿namespace BM.Tools.WebControls.MForm.Controls.Items
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Web.UI;    
    using System.Xml.XPath;

    using BM.Tools.WebControls.MForm.Controls.Helper;
    using BM.Tools.WebControls.MForm.Controls.Titles;

    /// <summary>
    /// A common class for all repeatable offspring item that are created from a definition object which inherits from <see cref="OffspringsOwner"/>.
    /// </summary>
    public abstract class OffspringsOwnerItem : OffspringItem
    {
        public const string OffspringsOwnerCssClass = "MForm-Own";

        private List<Offspring> offsprings;

        private FormTitleControl title;

        /// <summary>
        /// Initializes a new instance of the <see cref="OffspringsOwnerItem"/> class. 
        /// </summary>
        /// <param name="basis">
        /// The basis.
        /// </param>
        /// <param name="index">
        /// The index.
        /// </param>
        protected OffspringsOwnerItem(OffspringsOwner basis, int index)
                : base(basis, index)
        {
            DataBinding += OffspringsOwnerItemDataBinding;
        }

        /// <summary>
        /// Gets Basis.
        /// </summary>
        public new OffspringsOwner Basis
        {
            get
            {
                return base.Basis as OffspringsOwner;
            }
        }

        /// <summary>
        /// Gets ChildItems.
        /// </summary>
        public IEnumerable<OffspringItem> ChildItems
        {
            get
            {
                foreach (var offspring in Offsprings)
                {
                    foreach (var offspringItem in offspring.Items)
                    {
                        yield return offspringItem;
                    }
                }
            }
        }

        /// <summary>
        /// Gets Controls and if they are not initialized, creates them.
        /// </summary>
        public override ControlCollection Controls
        {
            get
            {
                EnsureChildControls();
                return base.Controls;
            }
        }

        /// <summary>
        /// Gets Offsprings.
        /// </summary>
        public ReadOnlyCollection<Offspring> Offsprings
        {
            get
            {
                if (offsprings == null || DesignMode)
                {
                    offsprings = RecalculateOffsprings();
                }

                return new ReadOnlyCollection<Offspring>(offsprings);
            }
        }

        /// <summary>
        /// Gets or sets Title.
        /// </summary>
        public FormTitleControl Title
        {
            get
            {
                if (title == null)
                {
                    title = new FormTitleControl(this);
                }

                return title;
            }

            set
            {
                title = value;
            }
        }        

        internal override void OnPostBack()
        {
            base.OnPostBack();
            EnsureChildControls();
        }

        internal List<Offspring> RecalculateOffsprings()
        {
            return new List<Offspring>(Controls.OfType<Offspring>(true));
        }

        /// <summary>
        /// Appends the resulting xml node of this offspring to the given parent node.
        /// </summary>
        /// <param name="parent">
        /// The parent node. 
        /// </param>
        protected override void AppendXmlToParent(IXPathNavigable parent)
        {            
            IXPathNavigable element = this.AppendElement(parent);
            foreach (IXmlEditor editor in this.GetChildrenXmlEditors())
            {
                if (editor.XmlEditEnabled)
                {
                    editor.AppendToParent(element);
                }
            }
        }

        /// <summary>
        /// creates inner controls along with the button container,
        /// adds the hidden input,
        /// instantiates the contents template
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            Controls.AddAt(0, Title);
            ITemplate contents = Basis.Contents;
            if (contents != null)
            {
                contents.InstantiateIn(this);
                PropagateDataSource();
            }
        }

        /// <summary>
        /// A method that is fired to propagate the data source from the offspring owner item to offsprings inside.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The event args.
        /// </param>
        protected void OffspringsOwnerItemDataBinding(object sender, System.EventArgs e)
        {
            PropagateDataSource();
        }

        /// <summary>
        /// checks validity of the item against its all constraints if it has to be validated
        /// </summary>
        /// <param name="validator">
        /// The validator.
        /// </param>
        /// <returns>
        /// is the item valid
        /// </returns>
        protected override bool ValidateObligatory(RootValidator validator)
        {
            var isValid = true;
            foreach (var editor in this.GetChildrenXmlEditors())
            {
                if (editor.Validate(validator) == false)
                {
                    isValid = false;
                }
            }

            return isValid && base.ValidateObligatory(validator);
        }

        /// <summary>
        /// Gets the current navigable and attaches it to child offsprings.
        /// </summary>
        protected virtual void PropagateDataSource()
        {
            if (Navigable == null)
            {
                return;
            }

            foreach (var offspring in Offsprings)
            {
                offspring.DataSource = Navigable;
            }
        }
    }
}